微服务
微服务介绍: 英文原文 中文翻译 或者 中文翻译
手动搭建 SpringBoot
代码地址
继承父工程
在 pom 文件中继承父工程
1 2 3 4 5 6
| <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> </parent>
|
引用 web 模块
1 2 3 4 5 6 7 8
| <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
|
添加 Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com.itguigu.springboot.controller;
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ResponseBody;
@Controller public class HelloController { @ResponseBody @GetMapping("/hello") public String hello(){ return "OK!+哈哈"; } }
|
添加主程序
添加主程序,主程序必须在所有所有 package 的父 package 下面(在什么 controller 上面的一层包下,因为他会去默认扫描他的子包下面的类,让我加入 IOC 容器中)如果需要单独指定那么可以使用 @ComponentScan
注解。主程序启动会启动内置的 Tomcat。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com.itguigu.springboot;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication public class MainApplication { public static void main(String[] args) { SpringApplication.run(MainApplication.class, args); } }
|
访问测试
直接右键启动 MainApplication, 默认端口为 8080, 默认没有上下文路径,直接访问 http://localhost:8080/hello 即可。
启动 Springboot 项目
方式1:右键 Run As
方式2:Boot Dashboard
SpringBoot 相关模块
Spring boot 中有很多 starter,常见信息如下:
简化部署
将 spring boot 项目打成 jar 包进行部署
先引入打包插件
1 2 3 4 5 6 7 8 9
| <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
|
引入之后直接 maven 运行 package 进行打包
打完包之后,直接 java -jar + 包名称运行即可
联网创建 SpringBoot 项目
代码地址
自动创建出来的项目中会在 src/main/resource 下面有 static 和 templates 文件夹,以及 application.propertis 文件,static 文件夹的访问路径就在根下面(里面放一张 xx.jpg,直接使用 http://localhost:8080/xx.jpg 就能访问到。)
可以 application.propertis 中进行配置:
1 2 3 4 5 6 7 8 9 10 11 12
| # 修改端口号 server.port=8081
# 修改上下文路径(一般不指定) # server.servlet.context-path=/a
# 修改session 超时时间,默认是 s server.servlet.session.timeout=1800 # 设置 tomcat 并发(500就差不多了) server.tomcat.max-threads=500 # 设置 url 编码问题(POST 请求 SpringBoot会自动配置编码过滤器,所以可以不管) server.tomcat.uri-encoding=UTF-8
|
yml 配置文件
yml 配置的优先级低于 properties 属性文件。SpringBoot 使用一个全局的配置文件,配置文件名是固定的 application.properties
或者 application.yml
。yml 文件使用缩进表示层级关系,缩进时不允许使用Tab键,只允许使用空格。缩进的空格数目不重要,只要相同层级的元素左侧对齐即可。大小写敏感。
yml 的配置格式是 k: v
形式,使用字面来书写【普通的值(数字,字符串,布尔)】,字符串默认不用加上单引号或者双引号。双引号不会转义字符串里面的特殊字符,单引号会转义特殊字符。更多配置可参考
SpringBoot 自动配置原理
SpringBoot 为什么能开箱即用呢?因为里面的所有东西都默认的配置好了。在 Maven Dependencies
中,有一个 spring-boot-autoconfigure-2.2.6.RELEASE.jar
的文件,里面的 MRTA-INF
中有一个 spring.factories
文件,其中的 Auto Configure
配置了所有的 Configuration
配置类。
这里以ThymeleafAutoConfiguration
为例子进行说明,查询该类,并进入
会看到类上有很多的注解,详细解释如下:
1 2 3 4 5 6 7 8 9 10
| @Configuration
@EnableConfigurationProperties(ThymeleafProperties.class) // 只有存在 TemplateMode SpringTemplateEngine 的时候 ThymeleafAutoConfiguration 类才生效(所以我们需要在 pom 中引入 Thymeleaf 的 starter,才能生效,否则没作用) @ConditionalOnClass({ TemplateMode.class, SpringTemplateEngine.class }) @AutoConfigureAfter({ WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class }) public class ThymeleafAutoConfiguration { ...... }
|
进入到 ThymeleafProperties
中查看相关配置,就能看到一些配置的默认值
总结如下:
- 主程序类标注了@SpringBootApplication 注解相当于标注了 @EnableAutoConfiguration,@EnableAutoConfiguration 开启 SpringBoot 的自动配置功能。
- SpringBoot帮我们配好了所有的场景
- SpringBoot中会有很多的 xxxxAutoConfigurarion(帮我们给容器中自动配好组件)
- xxxxAutoConfigurarion 给容器中配组件的时候,组件默认的属性一般都是从 xxxProperties中获取这些属性的值
- xxxProperties 是和配置文件绑定的(属性一一对应)
- 我们可以在 properties 文件或者 yml 文件中改掉这些默认配置
SpringBoot 整合 MyBatis(XML版)
代码地址
整合 MyBatis
联网创建项目,并导入对应依赖的 starter
这里选择 JDBC,MyBatis,MySQL,SpringWeb 这四个 Starter。
新建 application.yml 配置文件,内容如下:
1 2 3 4 5 6 7 8 9
| spring: datasource: username: root password: 123456 url: jdbc:mysql://127.0.0.1:3306/zcw?useSSL=false&useUnicode=true&characterEncoding=UTF-8 driver-class-name: com.mysql.cj.jdbc.Driver mybatis: config-location: classpath:mybatis/mybatis-config.xml mapper-locations: classpath:mybatis/mapper/*.xml
|
在 resource 目录下新建 mybatis 文件夹,并新建 mybatis-config.xml 配置文件和 mapper 子文件夹。mybatis-config.xml 中内容如下:
1 2 3 4 5 6
| <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration>
</configuration>
|
在 com.itguigu.springboot 包下新建子包,controller,service,bean,mapper,service.impl。
在 bean 中添加 TAdmin 类,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| package com.itguigu.springboot.bean;
public class TAdmin { private Integer id; private String loginacct; private String userpswd; private String username; private String email; private String createtime;
public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getLoginacct() { return loginacct; } public void setLoginacct(String loginacct) { this.loginacct = loginacct == null ? null : loginacct.trim(); } public String getUserpswd() { return userpswd; } public void setUserpswd(String userpswd) { this.userpswd = userpswd == null ? null : userpswd.trim(); } public String getUsername() { return username; } public void setUsername(String username) { this.username = username == null ? null : username.trim(); } public String getEmail() { return email; } public void setEmail(String email) { this.email = email == null ? null : email.trim(); } public String getCreatetime() { return createtime; } public void setCreatetime(String createtime) { this.createtime = createtime == null ? null : createtime.trim(); } }
|
controller 中新建 TAdminController, 内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.itguigu.springboot.controller;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;
import com.itguigu.springboot.bean.TAdmin; import com.itguigu.springboot.service.TAdminService;
@Controller public class TAdminController { @Autowired TAdminService adminService; @ResponseBody @RequestMapping("/getTAdminById/{id}") public TAdmin getTAdminById(@PathVariable("id") Integer id) { return adminService.getTAdminById(id); } }
|
service 中添加以下接口:
1 2 3 4 5 6 7 8
| package com.itguigu.springboot.service;
import com.itguigu.springboot.bean.TAdmin;
public interface TAdminService { public TAdmin getTAdminById(Integer id);
}
|
service.impl 中添加以下实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.itguigu.springboot.service.impl;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;
import com.itguigu.springboot.bean.TAdmin; import com.itguigu.springboot.mapper.TAdminMapper; import com.itguigu.springboot.service.TAdminService;
@Service public class TAdminServiceImpl implements TAdminService { @Autowired TAdminMapper tadminMapper; @Override public TAdmin getTAdminById(Integer id) { return tadminMapper.getTAdminById(id); } }
|
mapper 中新增 mapper 接口
1 2 3 4 5 6 7 8 9
| package com.itguigu.springboot.mapper;
import com.itguigu.springboot.bean.TAdmin;
public interface TAdminMapper {
TAdmin getTAdminById(Integer id); }
|
mapper.xml 中内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.itguigu.springboot.mapper.TAdminMapper">
<resultMap id="BaseResultMap" type="com.itguigu.springboot.bean.TAdmin"> <id column="id" jdbcType="INTEGER" property="id" /> <result column="loginacct" jdbcType="VARCHAR" property="loginacct" /> <result column="userpswd" jdbcType="CHAR" property="userpswd" /> <result column="username" jdbcType="VARCHAR" property="username" /> <result column="email" jdbcType="VARCHAR" property="email" /> <result column="createtime" jdbcType="CHAR" property="createtime" /> </resultMap> <select id="getTAdminById" resultMap="BaseResultMap"> select * from t_admin where id = #{id} </select> </mapper>
|
注意⚠️:要在主程序入口处加上 @MapperScan
用于扫描 mapper 中的包
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com.itguigu.springboot;
import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.itguigu.springboot.mapper") @SpringBootApplication public class SpringbootMybatisXmlApplication { public static void main(String[] args) { SpringApplication.run(SpringbootMybatisXmlApplication.class, args); } }
|
启动项目后直接访问 http://localhost:8080/getTAdminById/1 即可。
添加事务
使用注解开启事务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.itguigu.springboot;
import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.transaction.annotation.EnableTransactionManagement;
@EnableTransactionManagement
@MapperScan("com.itguigu.springboot.mapper") @SpringBootApplication public class SpringbootMybatisXmlApplication { public static void main(String[] args) { SpringApplication.run(SpringbootMybatisXmlApplication.class, args); } }
|
在 service impl 中具体的类或者方法上添加注解 @Transactional
表示添加事务。如果不想单独在方法上设置还可以将注解设置在类上,这样类中的方法都会有这个注解(生效的时候采用就近原则,方法上有就使用方法上的,方法上没有就使用类上的)。同样可以设置事务的隔离级别,传播行为等。设置信息可参考 Transactional 属性)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package com.itguigu.springboot.service.impl;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional;
import com.itguigu.springboot.bean.TAdmin; import com.itguigu.springboot.mapper.TAdminMapper; import com.itguigu.springboot.service.TAdminService;
@Transactional(readOnly = true) @Service public class TAdminServiceImpl implements TAdminService { @Autowired TAdminMapper tadminMapper; @Override public TAdmin getTAdminById(Integer id) { return tadminMapper.getTAdminById(id); } }
|
SpringBoot 整合 MyBatis(注解版)
代码地址
移除 mapper 配置文件
复制上面的项目,删除 resource
下的 mybatis 文件夹(也就是删除 mapper.xml 文件和 mybatis 配置文件)和 application.yml
中的 mybatis 相关配置。
在 com.itguigu.springboot.mapper
包下,mapper 接口的方法中添加各种操作注解,来进行相关操作。
1 2 3 4 5 6 7 8 9 10 11
| package com.itguigu.springboot.mapper;
import org.apache.ibatis.annotations.Select;
import com.itguigu.springboot.bean.TAdmin;
public interface TAdminMapper { @Select("select * from t_admin where id=#{id}") TAdmin getTAdminById(Integer id); }
|
启动项目后,直接访问 http://localhost:8080/getTAdminById/1 即可。
整合 Druid 数据源
配置文件方式
SpringBoot 默认的数据源驱动是 class com.zaxxer.hikari.HikariDataSource
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com.itguigu.springboot;
import javax.sql.DataSource;
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest class SpringbootMybatisXmlApplicationTests {
@Autowired DataSource dataSource; @Test void testDataSource() { System.out.println(dataSource.getClass()); } }
|
但是平时我们都使用 Druid,那么如何修改呢?
pom 文件引入 Druid
1 2 3 4 5 6
| <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.21</version> </dependency>
|
yml 文件中指定 datasource 的 type 的 com.alibaba.druid.pool.DruidDataSource
1 2 3 4 5 6 7
| spring: datasource: username: root password: 123456 url: jdbc:mysql://127.0.0.1:3306/zcw?useSSL=false&useUnicode=true&characterEncoding=UTF-8 driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource
|
再次运行测试用例,打印的 DataSource 的驱动就为 class com.alibaba.druid.pool.DruidDataSource
Config 配置类方式
新建 config 包,并新建 DruidDataSourceConfig
配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.itguigu.springboot.config;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
import com.alibaba.druid.pool.DruidDataSource;
@Configuration public class DruidDataSourceConfig { @ConfigurationProperties(prefix = "spring.datasource") @Bean public DataSource dataSource() throws SQLException{ DruidDataSource dataSource = new DruidDataSource(); dataSource.setFilters("stat"); return dataSource; } }
|
去除之前 yml 中配置的datasource 的 type。运行测试用例,打印的 DataSource 的驱动为 class com.alibaba.druid.pool.DruidDataSource
整合 Druid 监控
直接将以下代码粘贴到 DruidDataSourceConfig
配置类中,访问 http://localhost:8080/druid 使用上面配置的账户名密码登录后就能看到监控信息。完整代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| package com.itguigu.springboot.config;
import java.sql.SQLException; import java.util.Arrays; import java.util.HashMap; import java.util.Map;
import javax.sql.DataSource;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.support.http.StatViewServlet; import com.alibaba.druid.support.http.WebStatFilter;
@Configuration public class DruidDataSourceConfig { @ConfigurationProperties(prefix = "spring.datasource") @Bean public DataSource dataSource() throws SQLException { DruidDataSource dataSource = new DruidDataSource(); dataSource.setFilters("stat"); return dataSource; }
@Bean public ServletRegistrationBean statViewServlet() { ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); Map<String, String> initParams = new HashMap<>(); initParams.put("loginUsername", "admin"); initParams.put("loginPassword", "123456"); initParams.put("allow", ""); initParams.put("deny", "192.168.15.21"); bean.setInitParameters(initParams); return bean; }
@Bean public FilterRegistrationBean webStatFilter() { FilterRegistrationBean bean = new FilterRegistrationBean(); bean.setFilter(new WebStatFilter()); Map<String, String> initParams = new HashMap<>(); initParams.put("exclusions", "*.js,*.css,/druid/*"); bean.setInitParameters(initParams); bean.setUrlPatterns(Arrays.asList("/*")); return bean; } }
|
整合三大 Web 组件
之前的Web开发基于Servlet 2.5规范(在web.xml中配置Servlet,Filter,Listener)现在基于Servlet 3.0规范(基于配置类的方式声明对象:@WebServlet
@WebFilter
@WebListener
)。
注意⚠️:如果要让@WebServlet
@WebFilter
@WebListener
在 SpringBoot 中生效,需要在主程序的类上加上注解 @ServletComponentScan
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com.itguigu.springboot;
import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.transaction.annotation.EnableTransactionManagement;
@ServletComponentScan
@EnableTransactionManagement
@MapperScan("com.itguigu.springboot.mapper") @SpringBootApplication public class SpringbootMybatisXmlApplication { public static void main(String[] args) { SpringApplication.run(SpringbootMybatisXmlApplication.class, args); } }
|
Servlet
Servlet 以后我们在 springboot 中基本上不会用到的。但是还是介绍用法,servlet 的写法还是和之前一样的,直接继承 HttpServlet 然后重写 doget 方法。但是不需要在 web.xml 中进行配置,只需要在类上加上 @WebServlet(urlPatterns="/my")
注解即可。其中 /my
是请求路径。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package com.itguigu.springboot.web.servlet;
import java.io.IOException;
import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
@WebServlet(urlPatterns = "/my") public class MyServlet extends HttpServlet{ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("MyServlet do......."); } }
|
Filter
Filter 在以后会用到。写法还是一样,实现 Filter 接口,重写 init,doFilter,destroy 方法即可。也不需要在 web.xml 中进行配置,直接加上 @WebFilter(urlPatterns="/*")
注解即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package com.itguigu.springboot.web.filter;
import java.io.IOException;
import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter;
@WebFilter(urlPatterns = "/*") public class HelloFilter implements Filter{
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("HelloFilter............放行之前"); chain.doFilter(request, response); System.out.println("HelloFilter............放行之后"); } }
|
Listener
Listener 在以后会用到。写法还是一样,实现 ServletContextListener 接口,重写 contextDestroyed,contextInitialized 方法即可。也不需要在 web.xml 中进行配置,直接加上 @WebListener
注解即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package com.itguigu.springboot.web.litener;
import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener;
@WebListener public class HelloListener implements ServletContextListener{ @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("应用销毁了....HelloListener"); } @Override public void contextDestroyed(ServletContextEvent sce) { System.out.println("应用销毁了....HelloListener"); } }
|